package com.lt.flashcard.view;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zkoss.xel.fn.StringFns;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.metainfo.ComponentInfo;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.A;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Window;

import com.lt.flashcard.Utility;
import com.lt.flashcard.model.entity.ActionResult;
import com.lt.flashcard.model.entity.FlashcardSet;
import com.lt.flashcard.model.entity.Journey;
import com.lt.flashcard.model.entity.User;
import com.lt.flashcard.model.service.AAService;
import com.lt.flashcard.model.service.FlashcardService;
import com.lt.flashcard.model.service.FlashcardSetService;
import com.lt.flashcard.model.service.LearningService;
import com.lt.flashcard.model.service.MessageService;
import com.lt.flashcard.model.service.NotificationService;
import com.lt.flashcard.model.service.Repository;
import com.lt.flashcard.model.service.UserService;

public class DashboardCtrl extends SelectorComposer<Component> {

	private static final long serialVersionUID = 1L;
	
	private final Logger log = LoggerFactory.getLogger(DashboardCtrl.class);
	
	private User user = null;
	private User curUser = null; //current loged in user
	private long nu = 0;
	private boolean isFriend = true;
	private boolean isAdmin = false;
	private Journey journey;
	
	@Override
	public ComponentInfo doBeforeCompose(Page page, Component parent, ComponentInfo compInfo) {
		
		AAService asrv = Repository.getInstance().getAAService();
		String strUid = Executions.getCurrent().getParameter("uid");
		String uName = Executions.getCurrent().getParameter("uname");
		
		curUser = asrv.getCurrentUser();
		
		if(!Utility.isEmptyString(strUid) || !Utility.isEmptyString(uName)){
			UserService srv  =  Repository.getInstance().getUserService();
			user = Utility.isEmptyString(strUid) ? srv.findByUsername(uName) : srv.findByID(new Long(strUid));
			
			if(user == null){
				Utility.display404(false);
				return null;
			}
			if(user != null && curUser != null) {
				if(!user.getId().equals(curUser.getId())){
					nu = srv.getManualFriends(curUser, user);
					isFriend = srv.isFriend(curUser, user);
				}
			}
			
			//TODO check access to this profile
		} else {
    		if(!asrv.isLogin()) {
    			Utility.loginOrAccessDenied(false);
    			return null;
    		}
    		else {
    			String url = Utility.generateUrl("dashboard", curUser.getUsername(), null);
    			Utility.redirect(Utility.removeContextPath(url), false);
    			return null;
    		}
		}
		
		if(user != null && asrv.isAdmin(user)){
			if(curUser == null || (curUser != null && !user.getId().equals(curUser.getId()))){
				Utility.displayAccessDenied(false);
				return null;
			}
		}
		
		if(curUser != null && asrv.isAdmin(curUser))
			setAdmin(true);
		
		Utility.addOgTag(page,
				String.format("Góc học tập của %s", user.getUsername()),
				String.format("www.blueup.vn đã giúp %s đạt thành tích học tập vượt trội. Hãy tham gia Flashcard Blueup để trải nghiệm hiệu quả cùng hàng nghìn người khác", user.getUsername()),
				Utility.loadImageFromGridFS(user.getAvatar(), Utility.DEF_AVATAR));
		
		LearningService lsrv = Repository.getInstance().getLearningService();
		journey = lsrv.getCurrentJourney(user.getId());
		return super.doBeforeCompose(page, parent, compInfo);
	}
	
	public User getUser() {
		return user;
	}
	
	public long getNu(){
		return nu;
	}
	public boolean getIsFriend(){
		return isFriend;
	}
	
	private int _totalFc = -1;
	/**
	 * Return total number of flashcards of current user
	 * @return
	 */
	public int getTotalFlashcards() {
		if(_totalFc == -1) {
			FlashcardService srv = Repository.getInstance().getFlashcardService();
			_totalFc = srv.countFlashcardsOfUser(user);
		}
		return _totalFc;
	}
	
	/**
	 * Get top 10 bluenies of all users
	 * @return
	 */
	public ListModel<User> getTop10All() {
		List<User> lst = Repository.getInstance().getUserService().getTop10OfAll();
		return new ListModelList<User>(lst);
	}
	
	/**
	 * Get top 10 bluenies of all friends
	 * @return
	 */
	public ListModel<User> getTop10Friend() {
		List<User> lst = Repository.getInstance().getUserService().getTop10OfFriend(getUser());
		return new ListModelList<User>(lst);
	}
	
	public int getNumForTesting(FlashcardSet fcs) {
		FlashcardSetService srv = Repository.getInstance().getFlashcardSetService();
		return srv.getNumOfWaitingWordForTest(fcs);
	}
	
	public int getNumKnowCards(FlashcardSet fcs) {
		FlashcardSetService srv = Repository.getInstance().getFlashcardSetService();
		return srv.getNumOfKnowCards(fcs);
	}
	
	private final Map<Long, Object[]> _test017Cache = new HashMap<Long, Object[]>();
	public Object[] getTest017Status(FlashcardSet fcs) {
		if(!_test017Cache.containsKey(fcs.getId())) {
			int rs = getNumForTesting(fcs);
			String d = "";
			if(rs > 0)
				rs = 0;//go to test
			else {
				int fc = getNumFreshCards(fcs);
				if(fc == fcs.getTotalflashcards())
					rs = 1; //learn first
				else {
					LearningService srv = Repository.getInstance().getLearningService();
					rs = 2; //test in future
					Date dd = srv.getNextTestDate(fcs, new Date());
					if(dd != null)
						d = Utility.formatDate(dd);
					else {
						rs = 1;
						d = "";
					}
				}
			}
			_test017Cache.put(fcs.getId(), new Object[] {rs, d});
		}
		return _test017Cache.get(fcs.getId());
	}
	
	/**
	 * get round rank
	 */
	public double getRankRound(){
		UserService srv = Repository.getInstance().getUserService();
		int strRank = srv.getRank(getUser());
		double dr = new Double(strRank) / 10;
		
		double rr = Math.ceil(dr * 2);
		return rr;
	}
	
	public int getNumUnknowCards(FlashcardSet fcs) {
		FlashcardSetService srv = Repository.getInstance().getFlashcardSetService();
		return srv.getNumOfUnknowCards(fcs);
	}
	
	public int getNumNewCards(FlashcardSet fcs) {
		FlashcardSetService srv = Repository.getInstance().getFlashcardSetService();
		return srv.getNumOfNewCards(fcs);
	}
	
	public int getNumFreshCards(FlashcardSet fcs) {
		FlashcardSetService srv = Repository.getInstance().getFlashcardSetService();
		return srv.getNumOfFreshCards(fcs);
	}
	
	@Listen("onClick=#friend_request")
	public void saveNotificationFriendrequest(Event event){
		NotificationService nsrv = Repository.getInstance().getNotificationService();
		ActionResult rs = nsrv.addNotificationFriendRequest(curUser, user);
		if(rs.isError()) {
			Clients.evalJavaScript("showNotice('', '" + rs.getMessage() + "');");
		}
		else {
			Utility.redirect("dashboard.zul?uid=" + user.getId(), true);
		}
	}

	public Journey getJourney() {
		return journey;
	}

	public void setJourney(Journey journey) {
		this.journey = journey;
	}
	
	/**
	 * Check if user can get this item
	 * @param index
	 * @return
	 */
	public int checkAvailable(int index) {
		LearningService lsrv = Repository.getInstance().getLearningService();
		return lsrv.checkCanGetItem(getUser(), journey, index);
	}
	
	public boolean isOwner() {
		return user != null && curUser != null && user.getId().equals(curUser.getId());
	}
	
	/**
	 * Check is friend request has been sent
	 * @return
	 */
	public boolean isFriendRequest() {
		NotificationService srv = Repository.getInstance().getNotificationService();
		return srv.isSentFriendRequest(curUser.getId(), user.getId());
	}
	
	@Listen("onClick=.get_it")
	public void getJourneyItem(Event event) {
		A a = (A) event.getTarget();
		int index = (Integer) a.getAttribute("id");
		LearningService lsrv = Repository.getInstance().getLearningService();
		if(lsrv.getJourneyItem(getUser(), journey, index)) {
			if(isOwner())
				Utility.redirect("dashboard.zul", true);
			else
				Utility.redirect(Utility.removeContextPath(Utility.generateUrl("dashboard", getUser().getId(), null)), true);
		}
		else
			Clients.evalJavaScript("showNotice('', 'Không thể lấy item này')");
	}
	
	@Wire
	Textbox txtPrivateMsg;
	
	@Listen("onClick=#btnSendPrivateMsg")
	public void sendPrivateMessage() {
		if(txtPrivateMsg == null || Utility.isEmptyString(txtPrivateMsg.getValue())) {
			Clients.evalJavaScript("showNotice('', 'Bạn chưa nhập nội dung')");
		}
		else {
			//TODO filter content
			String content = txtPrivateMsg.getValue();
			content = StringFns.eatQuot(content);
			
			MessageService msrv = Repository.getInstance().getMessageService();
			msrv.sendNewMessage(curUser, getUser(), content);
			
			Clients.evalJavaScript("showNotice('', 'Tin nhắn đã được gửi thành công')");
			txtPrivateMsg.setValue("");
		}
	}

	/**
	 * @return the curUser
	 */
	public User getCurUser() {
		return curUser;
	}

	/**
	 * @param curUser the curUser to set
	 */
	public void setCurUser(User curUser) {
		this.curUser = curUser;
	}
	
	@Listen("onClick=#btn_compare")
	public void btn_compare() {
		//load dialog
		if(user != null && curUser != null && !user.getId().equals(curUser.getId())) {
			final Map<String, User> args = new HashMap<String, User>();
			args.put("you", curUser);
			args.put("friend", user);
			
			Window window = (Window) Executions.createComponents("/modal/dlgCompare.zul", null, args);
			window.doModal();
		}
	}

	public boolean isAdmin() {
		return isAdmin;
	}

	public void setAdmin(boolean isAdmin) {
		this.isAdmin = isAdmin;
	}
}